/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2025. All rights reserved.
 */

import path from 'path';

import { hvigorCore } from '@ohos/hvigor';
import { Component, ComponentPath } from '@ohos/sdkmanager-common';
import fse from 'fs-extra';

import { InjectConst } from '../../const/inject-const.js';
import { ProjectBuildProfile } from '../../options/build/project-build-profile.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';
import { SdkVersionEnum } from '../../version/sdk-version-enum.js';
import { SdkVersion } from '../../version/sdk-version.js';
import { DefaultSdk } from '../default-sdk.js';
import { SdkEtsComponent } from '../impl/sdk-ets-component.js';
import { SdkJsComponent } from '../impl/sdk-js-component.js';
import { SdkNativeComponent } from '../impl/sdk-native-component.js';
import { SdkPreviewerComponent } from '../impl/sdk-previewer-component.js';
import { SdkToolchainsComponent } from '../impl/sdk-toolchains-component.js';

import ApiMeta = ProjectBuildProfile.ApiMeta;

export abstract class CommonSdkInfo extends DefaultSdk {
  protected _log: OhosLogger = OhosLogger.getLogger(CommonSdkInfo.name);
  public sdkDir: string;
  protected sdkVersion: ApiMeta;
  protected jsComponent: SdkJsComponent | undefined;
  protected etsComponent: SdkEtsComponent | undefined;
  protected nativeComponent: SdkNativeComponent | undefined;
  protected toolchainsComponent: SdkToolchainsComponent | undefined;
  protected previewerComponent: SdkPreviewerComponent | undefined;

  protected constructor(sdkVersion: ApiMeta, sdkDir: string) {
    super();
    this.sdkVersion = sdkVersion;
    this.sdkDir = sdkDir;
  }

  /**
   * 获取当前sdk中对应api 的toolchains组件的小版本号
   *
   * @return {string | undefined}
   */
  getToolchainsComponentVersion(): string | undefined {
    return this.toolchainsComponent?.getComponentVersion().getVersion();
  }

  getModuleSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getModuleSchema() : '';
  }

  getAppSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getAppSchema() : '';
  }

  getAppConfigurationSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getAppConfigurationSchema() : '';
  }

  getStartWindowSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getStartWindowSchema() : '';
  }

  getSystemThemeSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getSystemThemeSchema() : '';
  }

  getInsightIntentSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getInsightIntentSchema() : '';
  }

  getUtdSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getUtdSchema() : '';
  }

  getFormSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getFormSchema() : '';
  }

  getPageSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getPageSchema() : '';
  }

  getRouterMapSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getRouterMapSchema() : '';
  }

  getShortcutsJsonSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getShortcutsJsonSchema() : '';
  }

  getAppStartupSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getAppStartupSchema() : '';
  }

  getHspStartupSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getHspStartupSchema() : '';
  }

  getHarStartupSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getHarStartupSchema() : '';
  }

  getSysCapSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getSysCapSchema() : '';
  }

  getPacSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getPacSchema() : '';
  }

  getSdkJsDir(): string {
    if (this.jsComponent) {
      return this.jsComponent.getBaseDir();
    }
    return '';
  }

  getSdkEtsDir(): string {
    return this.etsComponent ? this.etsComponent.getBaseDir() : '';
  }

  getSdkVersion(): number {
    return this.sdkVersion.version;
  }

  getSdkApi(): string {
    return this.sdkVersion.api;
  }

  getHapTobin(): string {
    return this.jsComponent!.getHapToBinFilePath();
  }

  getReleaseType(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getReleaseType() : 'Release';
  }

  getSdkNativeDir(): string {
    return this.nativeComponent!.getBaseDir();
  }

  getCmakeTool(): string {
    return this.nativeComponent!.getCmakeTool();
  }

  getNativeNinjaTool(): string {
    return this.nativeComponent!.getNinjaTool();
  }

  getNativeToolchain(): string {
    return this.nativeComponent!.getNativeToolchain();
  }

  getNdkVersion(): SdkVersion {
    return this.nativeComponent!.getComponentVersion();
  }

  getSdkToolchainsDir(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getBaseDir() : '';
  }

  getSdkLlvmStrip(): string {
    return this.nativeComponent!.getLlvmStrip();
  }

  getSdkLlvmReadElf(): string {
    return this.nativeComponent!.getLlvmReadElf();
  }

  getRestool(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getRestoolPath() : '';
  }

  getSysCapTool(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getSysCapToolPath() : '';
  }

  getSysCapFileInEts(): string {
    return this.etsComponent ? this.etsComponent.getSysCapFilePath() : '';
  }

  getSysCapFileInJs(): string {
    return this.jsComponent ? this.jsComponent.getSysCapFilePath() : '';
  }

  getVerifySignConfigTool(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getVerifySignConfigToolPath() : '';
  }

  getJsArkVersion(compatibleSdkVersion: number, compatibleSdkVersionStage?: string): string {
    if (!this.jsComponent) {
      return '';
    }

    if (this.findNoAbcTool(this.jsComponent.getJsLoaderPath())) {
      this._log.warn('Ark tools not found. Cannot get ark version.');
      return '';
    }

    const jsArkVersion = this.jsComponent.getCompatibleArkVersion(compatibleSdkVersion, compatibleSdkVersionStage);
    if (jsArkVersion && jsArkVersion !== '') {
      return jsArkVersion;
    }
    return this.jsComponent.getArkVersion();
  }

  getRichSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getRichSchema() : '';
  }

  getLiteSchema(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getLiteSchema() : '';
  }

  getEtsArkVersion(compatibleSdkVersion: number, compatibleSdkVersionStage?: string): string {
    if (!this.etsComponent) {
      return '';
    }

    if (this.findNoAbcTool(this.etsComponent.getEtsLoaderPath())) {
      this._log.warn('Ark tools not found. Cannot get ark version.');
      return '';
    }

    const etsArkVersion = this.etsComponent.getCompatibleArkVersion(compatibleSdkVersion, compatibleSdkVersionStage);
    if (etsArkVersion && etsArkVersion !== '') {
      return etsArkVersion;
    }
    return this.etsComponent.getArkVersion();
  }

  getEtsComponentVersion(): string {
    return this.etsComponent ? this.etsComponent.getComponentVersion().getVersion() : '';
  }

  getEtsComponentReleaseType(): string {
    return this.etsComponent ? this.etsComponent.getReleaseType() : 'Release';
  }

  getArkVersion(compatibleSdkVersion: number, compatibleSdkVersionStage?: string): string {
    const arkVersion = this.getEtsArkVersion(compatibleSdkVersion, compatibleSdkVersionStage);
    if (arkVersion && arkVersion !== '') {
      return arkVersion;
    }
    return this.getJsArkVersion(compatibleSdkVersion, compatibleSdkVersionStage);
  }

  getPackageTool(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getPackageToolPath() : '';
  }

  getBasePath(): string {
    return this.toolchainsComponent?.getBaseDir() ?? '';
  }

  getPreviewerCommonBinDir(): string {
    return this.previewerComponent?.getCommonBin() ?? '';
  }

  getPreviewerPermissionNames(): string[] {
    return this.previewerComponent?.getSdkPermissionNames() ?? [];
  }

  getPreviewerUserGrant(): string[] {
    return this.previewerComponent?.getSdkDefineUserGrant() ?? [];
  }

  allowSdkPermission(): boolean {
    return this.previewerComponent?.allowSdkPermission ?? false;
  }

  getSignDir(): string {
    return this.toolchainsComponent ? this.toolchainsComponent.getSignDir() : '';
  }

  getJsLoader(): string {
    return this.jsComponent ? this.jsComponent.getJsLoaderPath() : '';
  }

  getEtsLoader(): string {
    return this.etsComponent ? this.etsComponent.getEtsLoaderPath() : '';
  }

  getDriverBuild(): string {
    return this.etsComponent ? this.etsComponent.getBuildSystemPath() : '';
  }

  getOpenHarmonyEtsV2ApiPaths(): string[] {
    return this.etsComponent ? this.etsComponent.getOpenHarmonyEtsV2ApiPaths() : [];
  }

  getArkUIPlugin(): string {
    return this.etsComponent ? this.etsComponent.getArkUIPLuginPath() : '';
  }

  getArkUIMemoPlugin(): string {
    return this.etsComponent ? this.etsComponent.getArkUIMemoPluginPath() : '';
  }

  getArkUIInteropPlugin(): string {
    return this.etsComponent ? this.etsComponent.getArkUIInteropPluginPath() : '';
  }

  getRunEs2AbcStandalone(): string {
    return this.etsComponent ? this.etsComponent.getRunEs2AbcStandalone() : '';
  }

  getRunDeclgenStandalone(): string {
    return this.etsComponent ? this.etsComponent.getRunDeclgenStandalone() : '';
  }

  requireUISyntax(): boolean {
    if (this.jsComponent !== undefined && this.etsComponent !== undefined) {
      return this.jsComponent.requireUISyntax() || this.etsComponent.requireUISyntax();
    }
    if (this.etsComponent !== undefined) {
      return this.etsComponent.requireUISyntax();
    }
    if (this.jsComponent !== undefined) {
      return this.jsComponent.requireUISyntax();
    }

    // 此时sdk都没加载, 没有兼容性可言
    return false;
  }

  /**
   * 判断是否是preview构建，且sdk restool工具支持增量编译
   *
   * @param {boolean} isHarmonyOS 是否是HarmonyOS工程
   * @return {boolean} true是，false否
   */
  isPreviewCompileResourceIncrement(isHarmonyOS: boolean): boolean {
    const compileResInc: string | undefined = hvigorCore.getExtraConfig().get(InjectConst.PREVIEWER_COMPILE_RES_INC);
    const isSdkSupport = this.sdkVersion.version >= 9;
    return compileResInc === 'true' && isSdkSupport && !!this.toolchainsComponent?.supportCompileResourceIncrement(isHarmonyOS);
  }

  /**
   * 判断SDK版本是否支持Ohpm工程
   * @param isHarmonyOS
   */
  supportOhpmProject(isHarmonyOS: boolean): boolean {
    return !!this.toolchainsComponent?.supportOhpmProject(isHarmonyOS);
  }

  /**
   * hap-sign-tool.jar是否支持API函数调用
   * @param isHarmonyOS
   */
  supportHapSignToolApiCall(isHarmonyOS: boolean): boolean {
    const apiVersion = this.toolchainsComponent?.getComponentApiVersion();
    const componentVersion = this.toolchainsComponent?.getComponentVersion();
    if (!apiVersion || !componentVersion) {
      return false;
    }
    if (apiVersion > 12) {
      return true;
    } else if (apiVersion === 12) {
      return componentVersion.isHigherThan(SdkVersionEnum.SUPPORT_HAP_SIGN_TOOL_API_CALL_API12);
    } else if (apiVersion === 11) {
      if (isHarmonyOS) {
        return componentVersion.isHigherThan(SdkVersionEnum.HOS_SUPPORT_HAP_SIGN_TOOL_API_CALL_API11);
      } else {
        return componentVersion.isHigherThan(SdkVersionEnum.OHOS_SUPPORT_HAP_SIGN_TOOL_API_CALL_API11);
      }
    } else {
      return false;
    }
  }

  /**
   * 根据获取到的sdk-component名称创建不同的component实例
   *
   * @param component
   */
  protected initComponent(component: Component) {
    switch (component.getPath()) {
      case ComponentPath.JS:
        this.jsComponent = new SdkJsComponent(component);
        break;
      case ComponentPath.ETS:
        this.etsComponent = new SdkEtsComponent(component);
        break;
      case ComponentPath.TOOLCHAINS:
        this.toolchainsComponent = new SdkToolchainsComponent(component);
        break;
      case ComponentPath.NATIVE:
        this.nativeComponent = new SdkNativeComponent(component);
        break;
      case ComponentPath.PREVIEWER:
        this.previewerComponent = new SdkPreviewerComponent(component);
        break;
      default:
        break;
    }
  }

  private findNoAbcTool(loaderPath: string): boolean {
    const abcToolPath = path.resolve(loaderPath, 'bin', 'ark', 'ts2abc.js');
    return !abcToolPath || !fse.existsSync(abcToolPath);
  }
}
